package com.example.calculator_backend.service;

import com.example.calculator_backend.pojo.LoanRequest;
import com.example.calculator_backend.pojo.LoanResult;
import com.example.calculator_backend.pojo.PaymentDetail;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;

/**
 * @description: 贷款计算服务
 * @author: hdr
 * @PACKAGE_NAME: com.example.calculator_backend.service
 * @DATE: 2025/8/11
 */
public class LoanCalculator {

    // 精度设置
    private static final int SCALE = 2;
    private static final RoundingMode ROUNDING_MODE = RoundingMode.HALF_UP;

    /**
     * 计算贷款
     * @param req 贷款请求参数
     * @return 贷款计算结果
     */
    public static LoanResult calculate(LoanRequest req) {
        // 参数验证
        validateRequest(req);
        
        switch (req.getLoanType()) {
            case "商业贷款":
            case "公积金贷款":
                return calculateSingleLoan(
                        req.getAmount(),
                        req.getRate(),
                        req.getYears(),
                        req.getRepaymentType(),
                        req
                );
            case "组合贷款":
                BigDecimal totalInit = req.getBusinessAmount().add(req.getProvidentAmount());
                BigDecimal preAmt = req.getPrepaymentAmount();

                // 构建两个子请求，仅用于承载提前还款与先息参数，并按占比分摊提前还款额
                LoanRequest bizReq = new LoanRequest();
                bizReq.setPrepaymentMonth(req.getPrepaymentMonth());
                bizReq.setPrepaymentStrategy(req.getPrepaymentStrategy());
                bizReq.setInterestOnlyMonths(req.getInterestOnlyMonths());
                if (preAmt != null && totalInit.compareTo(BigDecimal.ZERO) > 0) {
                    BigDecimal ratio = req.getBusinessAmount().divide(totalInit, 10, ROUNDING_MODE);
                    bizReq.setPrepaymentAmount(preAmt.multiply(ratio));
                }

                LoanRequest provReq = new LoanRequest();
                provReq.setPrepaymentMonth(req.getPrepaymentMonth());
                provReq.setPrepaymentStrategy(req.getPrepaymentStrategy());
                provReq.setInterestOnlyMonths(req.getInterestOnlyMonths());
                if (preAmt != null && totalInit.compareTo(BigDecimal.ZERO) > 0) {
                    BigDecimal ratio = req.getProvidentAmount().divide(totalInit, 10, ROUNDING_MODE);
                    provReq.setPrepaymentAmount(preAmt.multiply(ratio));
                }

                LoanResult business = calculateSingleLoan(
                        req.getBusinessAmount(),
                        req.getBusinessRate(),
                        req.getYears(),
                        req.getRepaymentType(),
                        bizReq
                );
                LoanResult provident = calculateSingleLoan(
                        req.getProvidentAmount(),
                        req.getProvidentRate(),
                        req.getYears(),
                        req.getRepaymentType(),
                        provReq
                );
                return combineLoanResults(business, provident);
            default:
                throw new IllegalArgumentException("未知贷款类型: " + req.getLoanType());
        }
    }

    /**
     * 计算单一贷款
     * @param amount 贷款金额
     * @param rate 年利率
     * @param years 贷款年限
     * @param type 还款方式
     * @return 贷款计算结果
     */
    private static LoanResult calculateSingleLoan(BigDecimal amount, BigDecimal rate, BigDecimal years, String type, LoanRequest req) {
        // 计算总月数：年数 * 12，支持小数年限
        int months = years.multiply(new BigDecimal("12")).setScale(0, RoundingMode.HALF_UP).intValue();
        System.out.println("DEBUG: calculateSingleLoan - years = " + years + ", calculated months = " + months);
        BigDecimal monthlyRate = rate.divide(new BigDecimal("1200"), 10, ROUNDING_MODE); // 年利率/100/12

        LoanResult result = new LoanResult();
        List<PaymentDetail> schedule = new ArrayList<>();
        BigDecimal totalInterest = BigDecimal.ZERO;
        BigDecimal monthlyPayment = BigDecimal.ZERO;

        if ("先息后本".equals(type)) {
            BigDecimal remaining = amount;

            for (int i = 1; i <= months; i++) {
                BigDecimal interest = remaining.multiply(monthlyRate).setScale(SCALE, ROUNDING_MODE);
                BigDecimal principal = BigDecimal.ZERO.setScale(SCALE, ROUNDING_MODE);
                BigDecimal total = interest;

                // 提前还款
                if (req != null && req.getPrepaymentMonth() != null && req.getPrepaymentAmount() != null && req.getPrepaymentMonth() == i) {
                    BigDecimal preAmt = req.getPrepaymentAmount().min(remaining).setScale(SCALE, ROUNDING_MODE);
                    if (preAmt.compareTo(BigDecimal.ZERO) > 0) {
                        principal = principal.add(preAmt);
                        total = total.add(preAmt);
                        remaining = remaining.subtract(preAmt);
                    }
                }

                if (i == months) {
                    principal = principal.add(remaining);
                    total = interest.add(principal);
                    remaining = BigDecimal.ZERO;
                }

                totalInterest = totalInterest.add(interest);

                PaymentDetail pd = new PaymentDetail();
                pd.setMonthIndex(i);
                pd.setPrincipal(principal);
                pd.setInterest(interest);
                pd.setTotalPayment(total.setScale(SCALE, ROUNDING_MODE));
                pd.setRemainingPrincipal(remaining.max(BigDecimal.ZERO));
                schedule.add(pd);

                if (remaining.compareTo(BigDecimal.ZERO) <= 0) {
                    break;
                }
            }

            monthlyPayment = schedule.get(0).getTotalPayment();

        } else if ("等额本息".equals(type)) {
            // 每月还款 = 贷款本金 × 月利率 × (1 + 月利率)^还款月数 / [(1 + 月利率)^还款月数 - 1]
            BigDecimal ratePlusOne = monthlyRate.add(BigDecimal.ONE);
            BigDecimal ratePower = ratePlusOne.pow(months);
            BigDecimal numerator = amount.multiply(monthlyRate).multiply(ratePower);
            BigDecimal denominator = ratePower.subtract(BigDecimal.ONE);
            monthlyPayment = numerator.divide(denominator, SCALE, ROUNDING_MODE);
            
            BigDecimal remaining = amount;
            BigDecimal totalPrincipal = BigDecimal.ZERO;

            for (int i = 1; i < months; i++) {
                BigDecimal interest = remaining.multiply(monthlyRate).setScale(SCALE, ROUNDING_MODE);
                BigDecimal principal = monthlyPayment.subtract(interest);
                remaining = remaining.subtract(principal);
                totalPrincipal = totalPrincipal.add(principal);

                // 提前还款
                if (req != null && req.getPrepaymentMonth() != null && req.getPrepaymentAmount() != null && req.getPrepaymentMonth() == i) {
                    BigDecimal preAmt = req.getPrepaymentAmount().min(remaining.max(BigDecimal.ZERO)).setScale(SCALE, ROUNDING_MODE);
                    if (preAmt.compareTo(BigDecimal.ZERO) > 0) {
                        principal = principal.add(preAmt);
                        remaining = remaining.subtract(preAmt);

                        // 策略
                        if ("减少月供".equals(req.getPrepaymentStrategy())) {
                            int remainingMonths = months - i;
                            if (remainingMonths > 0 && remaining.compareTo(BigDecimal.ZERO) > 0) {
                                BigDecimal rpPlusOne = monthlyRate.add(BigDecimal.ONE);
                                BigDecimal rpPower = rpPlusOne.pow(remainingMonths);
                                BigDecimal num = remaining.multiply(monthlyRate).multiply(rpPower);
                                BigDecimal den = rpPower.subtract(BigDecimal.ONE);
                                monthlyPayment = num.divide(den, SCALE, ROUNDING_MODE);
                            }
                        }
                    }
                }

                totalInterest = totalInterest.add(interest);
                
                PaymentDetail pd = new PaymentDetail();
                pd.setMonthIndex(i);
                pd.setPrincipal(principal);
                pd.setInterest(interest);
                pd.setTotalPayment(monthlyPayment);
                pd.setRemainingPrincipal(remaining.max(BigDecimal.ZERO));
                schedule.add(pd);
            }
            
            // 最后一个月，本金 = 剩余本金，确保总本金等于贷款金额
            if (months > 0) {
                BigDecimal interest = remaining.multiply(monthlyRate).setScale(SCALE, ROUNDING_MODE);
                BigDecimal principal = remaining; // 最后一个月本金 = 剩余本金
                BigDecimal total = principal.add(interest);
                
                totalPrincipal = totalPrincipal.add(principal);
                remaining = BigDecimal.ZERO;
                totalInterest = totalInterest.add(interest);

                PaymentDetail pd = new PaymentDetail();
                pd.setMonthIndex(months);
                pd.setPrincipal(principal);
                pd.setInterest(interest);
                pd.setTotalPayment(total);
                pd.setRemainingPrincipal(BigDecimal.ZERO);
                schedule.add(pd);
            }

        } else if ("等额本金".equals(type)) {
            // 使用四舍五入计算每月本金，确保总本金等于贷款金额
            BigDecimal totalPrincipal = BigDecimal.ZERO;
            BigDecimal remaining = amount;
            
            // 先计算前N-1个月的本金
            for (int i = 1; i < months; i++) {
                BigDecimal interest = remaining.multiply(monthlyRate).setScale(SCALE, ROUNDING_MODE);
                BigDecimal principal = amount.divide(new BigDecimal(months), SCALE, ROUNDING_MODE);
                BigDecimal total = principal.add(interest);
                
                totalPrincipal = totalPrincipal.add(principal);
                remaining = remaining.subtract(principal);
                totalInterest = totalInterest.add(interest);

                PaymentDetail pd = new PaymentDetail();
                pd.setMonthIndex(i);
                pd.setPrincipal(principal);
                pd.setInterest(interest);
                pd.setTotalPayment(total);
                pd.setRemainingPrincipal(remaining.max(BigDecimal.ZERO));
                schedule.add(pd);
            }
            
            // 最后一个月，本金 = 剩余本金，确保总本金等于贷款金额
            if (months > 0) {
                BigDecimal interest = remaining.multiply(monthlyRate).setScale(SCALE, ROUNDING_MODE);
                BigDecimal principal = remaining; // 最后一个月本金 = 剩余本金
                BigDecimal total = principal.add(interest);
                
                totalPrincipal = totalPrincipal.add(principal);
                remaining = BigDecimal.ZERO;
                totalInterest = totalInterest.add(interest);

                PaymentDetail pd = new PaymentDetail();
                pd.setMonthIndex(months);
                pd.setPrincipal(principal);
                pd.setInterest(interest);
                pd.setTotalPayment(total);
                pd.setRemainingPrincipal(BigDecimal.ZERO);
                schedule.add(pd);
            }

            monthlyPayment = schedule.get(0).getTotalPayment(); // 第一个月
        } else {
            throw new IllegalArgumentException("未知还款方式: " + type);
        }

        result.setMonthlyPayment(monthlyPayment);
        result.setTotalInterest(totalInterest);
        result.setTotalRepayment(amount.add(totalInterest));
        result.setSchedule(schedule);
        return result;
    }

    /**
     * 合并组合贷款结果
     * @param a 第一个贷款结果
     * @param b 第二个贷款结果
     * @return 合并后的贷款结果
     */
    private static LoanResult combineLoanResults(LoanResult a, LoanResult b) {
        LoanResult combined = new LoanResult();
        combined.setMonthlyPayment(a.getMonthlyPayment().add(b.getMonthlyPayment()));
        combined.setTotalInterest(a.getTotalInterest().add(b.getTotalInterest()));
        combined.setTotalRepayment(a.getTotalRepayment().add(b.getTotalRepayment()));

        List<PaymentDetail> schedule = new ArrayList<>();
        for (int i = 0; i < a.getSchedule().size(); i++) {
            PaymentDetail pd = new PaymentDetail();
            pd.setMonthIndex(i + 1);
            pd.setPrincipal(a.getSchedule().get(i).getPrincipal().add(b.getSchedule().get(i).getPrincipal()));
            pd.setInterest(a.getSchedule().get(i).getInterest().add(b.getSchedule().get(i).getInterest()));
            pd.setTotalPayment(a.getSchedule().get(i).getTotalPayment().add(b.getSchedule().get(i).getTotalPayment()));
            pd.setRemainingPrincipal(a.getSchedule().get(i).getRemainingPrincipal().add(b.getSchedule().get(i).getRemainingPrincipal()));
            schedule.add(pd);
        }

        combined.setSchedule(schedule);
        return combined;
    }

    /**
     * 验证请求参数
     * @param req 贷款请求参数
     */
    private static void validateRequest(LoanRequest req) {
        if (req == null) {
            throw new IllegalArgumentException("请求参数不能为空");
        }
        
        // 添加调试日志
        System.out.println("DEBUG: 接收到的请求参数:");
        System.out.println("DEBUG: years = " + req.getYears() + " (类型: " + (req.getYears() != null ? req.getYears().getClass().getSimpleName() : "null") + ")");
        System.out.println("DEBUG: loanType = " + req.getLoanType());
        System.out.println("DEBUG: repaymentType = " + req.getRepaymentType());
        
        if (req.getLoanType() == null || req.getLoanType().trim().isEmpty()) {
            throw new IllegalArgumentException("贷款类型不能为空");
        }
        
        if (req.getRepaymentType() == null || req.getRepaymentType().trim().isEmpty()) {
            throw new IllegalArgumentException("还款方式不能为空");
        }
        
        if (req.getYears() == null || req.getYears().compareTo(BigDecimal.ZERO) <= 0 || req.getYears().compareTo(new BigDecimal("50")) > 0) {
            throw new IllegalArgumentException("贷款年限必须在1-50年之间");
        }
        
        // 验证总期限
        int totalMonths = req.getYears().multiply(new BigDecimal("12")).setScale(0, RoundingMode.HALF_UP).intValue();
        System.out.println("DEBUG: 计算得到的总月数 = " + totalMonths);
        if (totalMonths <= 0 || totalMonths > 600) {
            throw new IllegalArgumentException("贷款总期限必须在1个月-50年之间");
        }

        switch (req.getLoanType()) {
            case "商业贷款":
            case "公积金贷款":
                if (req.getAmount() == null || req.getAmount().compareTo(BigDecimal.ZERO) <= 0) {
                    throw new IllegalArgumentException("贷款金额必须大于0");
                }
                if (req.getRate() == null || req.getRate().compareTo(BigDecimal.ZERO) <= 0) {
                    throw new IllegalArgumentException("贷款利率必须大于0");
                }
                break;
            case "组合贷款":
                if (req.getBusinessAmount() == null || req.getBusinessAmount().compareTo(BigDecimal.ZERO) <= 0) {
                    throw new IllegalArgumentException("商业贷款金额必须大于0");
                }
                if (req.getBusinessRate() == null || req.getBusinessRate().compareTo(BigDecimal.ZERO) <= 0) {
                    throw new IllegalArgumentException("商业贷款利率必须大于0");
                }
                if (req.getProvidentAmount() == null || req.getProvidentAmount().compareTo(BigDecimal.ZERO) <= 0) {
                    throw new IllegalArgumentException("公积金贷款金额必须大于0");
                }
                if (req.getProvidentRate() == null || req.getProvidentRate().compareTo(BigDecimal.ZERO) <= 0) {
                    throw new IllegalArgumentException("公积金贷款利率必须大于0");
                }
                break;
            default:
                throw new IllegalArgumentException("不支持的贷款类型: " + req.getLoanType());
        }
    }
}

